// 属性装饰器
const proDeco: PropertyDecorator = (
    target: object,
    propertyKey: string | symbol,
) => {
    console.log(target);
    console.log(propertyKey);
};

@classDecorator
export class User {
    private title: string;
    constructor(title: string) {
        this.title = title;
    }
    @warpMethonDecorator(10)
    static hello() {
        console.log('原始hello');
    }
    @methodDecorator
    greet() {
        console.log('原始greet');
    }
    @propertyDecorator
    age: number = 20;
    @proDeco
    address: string = '4444';
}

// 定义一个类修饰器， 只需要定义一个参数
/**
 *
 * @param TargetConstructor // 被装饰类类型
 * @returns // 修饰后的匿名类
 */
function classDecorator<T extends { new (...args: any[]): object }>(
    TargetConstructor: T,
) {
    console.log('被装饰类名称', TargetConstructor.name); // 可以根据不同的类分别处理
    // 返回继承于原生类的匿名类
    TargetConstructor.prototype.yhMethod1 = () => {
        console.log('装饰增加的yhMethod1方法');
    };
    return class extends TargetConstructor {
        private registerOrigin = 'WEB-SITE';
        private yhMethod = () => {
            console.log('装饰增加的yhMethod方法');
        };
    };
}

// 定义一个 方法修饰器
/**
 * @param target // 被装饰类
 * @param propertyKey // 被装饰方法名
 * @param descriptor // 方法属性
 * @returns // 装饰后方法返回值
 */
function methodDecorator(
    target: object,
    propertyKey: PropertyKey,
    descriptor: PropertyDescriptor,
) {
    console.log('方法装饰器 target:', target);
    console.log('方法装饰器 propertyKey:', propertyKey);
    const value = descriptor.value; // 保存原生函数
    descriptor.value = function (...args: any[]) {
        const result = value.apply(this, args); // 执行原生函数
        //...
        return result + '##';
    };
    return descriptor;
}
// 自定义包装 方法装饰器， 可传参   装饰器工厂
function warpMethonDecorator(n: number) {
    console.log('warpMethonDecorator', n);
    return (
        target: object,
        propertyKey: PropertyKey,
        descriptor: PropertyDescriptor,
    ) => {
        console.log('warpMethonDecorator n:', n);
        console.log('方法装饰器 target:', target);
        console.log('方法装饰器 propertyKey:', propertyKey);
        const value = descriptor.value; // 保存原生函数
        descriptor.value = function (...args: any[]) {
            const result = value.apply(this, args); // 执行原生函数
            //...
            return result + '##';
        };
        return descriptor;
    };
}

// 属性和参数装饰器函数
/**
 *
 * @param target // 被装饰类
 * @param propertyKey // 属性或者参数名称
 */
function propertyDecorator(target: any, propertyKey: string) {
    let value = target[propertyKey];

    // 属性 getter
    const getter = function () {
        console.log(`Getting value of property ${propertyKey}: ${value}`);
        return value;
    };

    // 属性 setter
    const setter = function (newValue: any) {
        console.log(`Setting value of property ${propertyKey} to: ${newValue}`);
        value = newValue;
    };

    // 重新定义属性
    Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true,
    });
}

function testUserRegister() {
    const user = new User('Tony');
    console.log(user);
    // console.log(User.hello());
    // console.log(user.greet());
    // user['yhMethod1']();
    // for (const key in user) {
    //     if (Object.prototype.hasOwnProperty.call(user, key)) {
    //         // const element = user[key];
    //         console.log(key);
    //     }
    // }
    // console.log(user.age);
    // user.age = 30;
    // console.log(user.age);
}

testUserRegister();
